package org.spring.blog.service.impl;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.spring.blog.dao.ArticleNoContentDao;
import org.spring.blog.dao.CommentDao;
import org.spring.blog.pojo.ArticleNoContent;
import org.spring.blog.pojo.Comment;
import org.spring.blog.pojo.LRPageList;
import org.spring.blog.pojo.User;
import org.spring.blog.response.ResponseResult;
import org.spring.blog.response.ResponseState;
import org.spring.blog.service.ICommentService;
import org.spring.blog.service.IUserService;
import org.spring.blog.utils.LRConstants;
import org.spring.blog.utils.RedisUtil;
import org.spring.blog.utils.SnowflakeIdWorker;
import org.spring.blog.utils.TextUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.transaction.Transactional;
import java.util.Date;

@Service
@Transactional
public class CommentService implements ICommentService {

    @Autowired
    SnowflakeIdWorker snowflakeIdWorker;

    @Autowired
    CommentDao commentDao;

    @Autowired
    ArticleNoContentDao articleNoContentDao;

    @Autowired
    RedisUtil redisUtil;

    @Autowired
    Gson gson;
    @Autowired
    IUserService userService;

    /**
     * 添加评论
     *
     * @param _comment 评论对象
     * @return 自定义返回对象
     */
    @Override
    public ResponseResult insert(Comment _comment) {
        // check data
        User userIsLogin = userService.checkUserIsLogin();

        if (userIsLogin == null) {
            return ResponseResult.failed(ResponseState.user_not_login_message, ResponseState.user_not_login_code);
        }

        if (TextUtil.isEmpty(_comment.getArticleId()) && TextUtil.isEmpty(_comment.getContent())) {
            return ResponseResult.failed(ResponseState.input_data_not_complete_message, ResponseState.input_data_not_complete_code);
        }
        ArticleNoContent oneById = articleNoContentDao.findOneById(_comment.getArticleId());

        if (oneById == null) {
            return ResponseResult.failed(ResponseState.data_not_have_message, ResponseState.data_not_have_code);
        }
        // complete data
        _comment.setId(String.valueOf(snowflakeIdWorker.nextId()))
                .setCreateTime(new Date())
                .setUpdateTime(new Date())
                .setUserAvatar(userIsLogin.getAvatar())
                .setUserName(userIsLogin.getUserName())
                .setUserId(userIsLogin.getId())
                .setState(LRConstants.db_publish_status);
        // save data
        commentDao.save(_comment);

        // change cache
        redisUtil.del(constant.redis_comment_first_page_cache + _comment.getArticleId());

        // return data
        return ResponseResult.success();
    }


    /**
     * 获取文章评论列表
     *
     * @param _articleId 文章id
     * @param _page      页码
     * @param _size      页面大小
     * @return 自定义返回对象
     */
    @Override
    public ResponseResult list(String _articleId, int _page, int _size) {
        _page = Math.max(_page, LRConstants.list_default_page_num);
        _size = Math.max(_size, LRConstants.list_min_page_size);

        // 如果是第一页，先从缓存中获取
        if (_page == 1) {
            String cacheJson = (String) redisUtil.get(constant.redis_comment_first_page_cache + _articleId);

            if (!TextUtil.isEmpty(cacheJson)) {
                LRPageList<Comment> result = gson.fromJson(cacheJson, new TypeToken<LRPageList<Comment>>() {
                }.getType());

                return ResponseResult.success().setData(result);
            }
        }

        Sort sort = new Sort(Sort.Direction.DESC, "state", "createTime");

        Pageable pageRequest = PageRequest.of(_page - 1, _size, sort);

        Page<Comment> all = commentDao.findAll(new Specification<Comment>() {
            private static final long serialVersionUID = -4212218329938332849L;

            @Override
            public Predicate toPredicate(Root<Comment> _root, CriteriaQuery<?> _criteriaQuery, CriteriaBuilder _criteriaBuilder) {
                return _criteriaBuilder.equal(_root.get("articleId").as(String.class), _articleId);
            }
        }, pageRequest);

        LRPageList<Comment> result = new LRPageList<>(all.getContent(), _page, all.getTotalElements(), all.getSize());

        // add cache
        if (_page == 1) {
            redisUtil.set(constant.redis_comment_first_page_cache + _articleId, gson.toJson(result), LRConstants.TimeValue.min_s * 10);
        }
        return ResponseResult.success().setData(result);
    }

    @Override
    public ResponseResult delete(String _id) {
        // check data
        User userIsLogin = userService.checkUserIsLogin();

        if (userIsLogin == null) {
            return ResponseResult.failed(ResponseState.user_not_login_message, ResponseState.user_not_login_code);
        }

        Comment oneById = commentDao.findOneById(_id);

        if (oneById == null) {
            return ResponseResult.failed(ResponseState.data_not_have_message, ResponseState.data_not_have_code);
        }

        // delete main data
        if (userIsLogin.getId().equals(oneById.getUserId())) {
            // 自己可以删除自己的评论
            commentDao.deleteById(oneById.getId());
        } else if (userIsLogin.getRoles().equals(IUserService.constant.DB_ROLE_ADMIN)) {
            // 管理员可以删除评论
            commentDao.deleteById(oneById.getId());
        } else {
            return ResponseResult.failed(ResponseState.no_power_message, ResponseState.no_power_code);
        }
        // delete cache data
        redisUtil.del(constant.redis_comment_first_page_cache + oneById.getArticleId());

        return ResponseResult.success();
    }

    /**
     * 查询评论
     *
     * @param _id 评论id
     * @return 自定义返回对象
     */
    @Override
    public ResponseResult query(String _id) {
        Comment oneById = commentDao.findOneById(_id);

        if (oneById == null) {
            return ResponseResult.failed(ResponseState.data_not_have_message, ResponseState.data_not_have_code);
        }

        return ResponseResult.success().setData(oneById);
    }

    /**
     * 置顶评论
     *
     * @param _id 评论id
     * @return 自定义返回对象
     */
    @Override
    public ResponseResult topCommit(String _id) {
        Comment oneById = commentDao.findOneById(_id);
        // check data
        if (oneById == null) {
            return ResponseResult.failed(ResponseState.data_not_have_message, ResponseState.data_not_have_code);
        }

        // change data
        switch (oneById.getState()) {
            case LRConstants.db_publish_status:
                oneById.setState(LRConstants.db_top_status);
                break;
            case LRConstants.db_top_status:
                oneById.setState(LRConstants.db_publish_status);
                break;
            default:
                return ResponseResult.failed(ResponseState.not_support_operation_message, ResponseState.not_support_operation_code);
        }

        // change cache
        redisUtil.del(constant.redis_comment_first_page_cache + oneById.getArticleId());

        return ResponseResult.success();
    }

    /**
     * 获取评论数量
     *
     * @return 自定义返回对象
     */
    @Override
    public ResponseResult getCommentCount() {
        long count = commentDao.count();
        return ResponseResult.success().setData(count);
    }

    /**
     * 管理中心 获取评论列表
     *
     * @param _page 页码
     * @param _size 页面大小
     * @return 自定义返回对象
     */
    @Override
    public ResponseResult listForAdmin(int _page, int _size) {
        _page = Math.max(_page, LRConstants.list_default_page_num);
        _size = Math.max(_size, LRConstants.list_min_page_size);

        Sort sort = new Sort(Sort.Direction.DESC, "state", "createTime");

        Pageable pageRequest = PageRequest.of(_page - 1, _size, sort);

        Page<Comment> all = commentDao.findAll(pageRequest);

        LRPageList<Comment> result = new LRPageList<>(all.getContent(), _page, all.getTotalElements(), all.getSize());

        return ResponseResult.success().setData(result);
    }
}